// 2025/4/7: 首个版本
// 2025/4/18: 增加仪表盘标识大类
// 2025/6/12: 协议名常量改为public

package com.appox.samples;

import com.appox.Sample;
import com.appox.GeneralSample;
import com.appox.GeneralElement;
import com.appox.Types;
import java.util.ArrayList;
import java.util.List;

/**
 * 图像标签样本数据类
 */
public class ImageLabelSample extends Sample {

    /**
     * 图像标签类型
     */
    public enum ImageLabelClass {
        UNKNOWN(0), // 未知

        AUTO(100), // General automobile / 机动车大类
        CAR(101), // 轿车
        BUS(102), // 大巴
        MIDIBUS(103), // 小巴
        TRUCK(104), // 货车
        VAN(105), // 面包车
        SEMITRAILER(106), // 货柜车
        TRAILER(107), // 拖车
        SUV(108), // SUV
        TINY_CAR(109), // 微型车

        MINOR(200), // General vulnerable road user / 弱势参与者大类
        PED(201), // Pedestrian / 行人
        BICYCLE(202), // 自行车
        TRICYCLE(203), // 三轮车
        MOTORBIKE(204), // 摩托车
        WHEELCHAIR(205), // 轮椅
        ANIMAL(206), // 动物

        STATIC(300), // General static object / 静态目标大类
        ZEBRA_CROSSING(301), // 斑马线
        TRAFFIC_LIGHT(302), // 交通灯
        TRAFFIC_SIGN(303), // 交通信号
        PARKING_SLOT(304), // 车位
        CONE(305), // 锥形路障
        MANHOLE_COVER(306), // 井盖
        PATCH(307), // 路面补丁
        GANTRY(308), // 龙门架
        POLE(309), // 竖杆
        TREE(310), // 树木
        VEGETATION(311), // 灌木
        BUILDING(312), // 建筑物

        DASHBOARD(1000), // Dashboard signal / 仪表盘标识大类
        AIRBAG(1001), // 安全气囊
        ABS(1002), // 防抱死制动
        BRAKE_SYSTEM_FAILURE(1003), // 刹车系统故障
        CHARGING_SYSTEM_FAILURE(1004), // 充电系统故障
        CENTRAL_WARNING_LAMP(1005), // 中央警告灯
        COOLING_SYSTEM_FAILURE(1006), // 冷却系统故障
        DOORS_OPEN(1007), // 车门未关
        ELECTRONIC_POWER_STEERING(1008), // 转向助力
        ELECTRONIC_STABILITY(1009), // 电子稳定性(ESC)
        ENGINE_PREHEATING(1010), // 发动机预热
        FRONT_FOG_LIGHT(1011), // 前雾灯
        LANE_DEPARTURE_WARNING(1012), // 车道偏离预警
        LOW_BEAM(1013), // 近光灯
        LOW_ENGINE_OIL_WARNING(1014), // 低燃油警告
        SEAT_BELT(1015), // 安全带提醒
        SIDE_LAMP(1016), // 示廓灯
        TYRE_PRESSURE_MONITORING(1017), // 胎压异常
        WASHER_FLUID(1018); // 玻璃水不足
        
        private final int value;
        
        ImageLabelClass(int value) {
            this.value = value;
        }
        
        public int getValue() {
            return value;
        }
        
        public static ImageLabelClass fromValue(int value) {
            for (ImageLabelClass cls : ImageLabelClass.values()) {
                if (cls.getValue() == value) {
                    return cls;
                }
            }
            return UNKNOWN;
        }
    }

    /**
     * 图像标签
     */
    public static class ImageLabel {
        private int id; // 标签ID
        private ImageLabelClass labelClass; // 标签类型
        private Double classConfidence; // [%] Classification confidence / 分类置信度
        private Double distance; // [m] Average distance between the label's pixels to the camera (along x axis of camera coordinate system) / 标签距摄像头的平均距离（沿摄像头x轴方向）
        private Types.FloatRect rect; // [pix] Border of the label / 标签矩形框
        private String description; // 描述信息
        
        public ImageLabel() {
            this.labelClass = ImageLabelClass.UNKNOWN;
        }
        
        public int getId() {
            return id;
        }
        
        public void setId(int id) {
            this.id = id;
        }
        
        public ImageLabelClass getLabelClass() {
            return labelClass;
        }
        
        public void setLabelClass(ImageLabelClass labelClass) {
            this.labelClass = labelClass;
        }
        
        public Double getClassConfidence() {
            return classConfidence;
        }
        
        public void setClassConfidence(Double classConfidence) {
            this.classConfidence = classConfidence;
        }
        
        public Double getDistance() {
            return distance;
        }
        
        public void setDistance(Double distance) {
            this.distance = distance;
        }
        
        public Types.FloatRect getRect() {
            return rect;
        }
        
        public void setRect(Types.FloatRect rect) {
            this.rect = rect;
        }
        
        public String getDescription() {
            return description;
        }
        
        public void setDescription(String description) {
            this.description = description;
        }
    }
    
    private Types.IntSize imageSize; // [pix] 图像尺寸
    private List<ImageLabel> labels; // List of labels / 标签列表

    /**
     * 构造函数
     */
    public ImageLabelSample() {
        labels = new ArrayList<>();
    }
    
    /**
     * 获取图像尺寸
     */
    public Types.IntSize getImageSize() {
        return imageSize;
    }
    
    /**
     * 设置图像尺寸
     */
    public void setImageSize(Types.IntSize imageSize) {
        this.imageSize = imageSize;
    }
    
    /**
     * 获取标签列表
     */
    public List<ImageLabel> getLabels() {
        return labels;
    }
    
    /**
     * 设置标签列表
     */
    public void setLabels(List<ImageLabel> labels) {
        this.labels = labels;
    }
    
    /**
     * 获取通用样本协议
     */
    @Override
    public String getGeneralSampleProtocol() {
        return TARGET_PROTOCOL;
    }
    
    /**
     * 获取通用样本协议列表
     */
    @Override
    public String[] getGeneralSampleProtocols() {
        return PROTOCOLS;
    }
    
    /**
     * 将图像标签样本转换为通用样本
     */
    public GeneralSample toGeneralSample(int channel) {
        GeneralSample sample = new GeneralSample();
        sample.setTime(this);
        sample.setProtocol(TARGET_PROTOCOL);
        sample.setChannel(channel);
        
        // 8 fixed fields + 16 fields per label
        GeneralElement[] data = new GeneralElement[8 + 16 * labels.size()];
        
        // 初始化所有元素
        for (int i = 0; i < data.length; i++) {
            data[i] = new GeneralElement();
        }
        
        // 设置通道相关信息和图像尺寸
        data[0] = new GeneralElement((double)channel);
        if (imageSize != null) {
            data[1] = new GeneralElement((double)imageSize.getWidth());
            data[2] = new GeneralElement((double)imageSize.getHeight());
        }
        data[3] = new GeneralElement((double)labels.size());
        // 保留字段4-7保持为空
        
        int baseIndex = 8;
        for (int i = 0; i < labels.size(); i++) {
            ImageLabel label = labels.get(i);
            data[baseIndex + 0] = new GeneralElement((double)label.getLabelClass().getValue());
            data[baseIndex + 1] = new GeneralElement((double)label.getId());
            if (label.getDistance() != null) data[baseIndex + 2] = new GeneralElement(label.getDistance());
            
            // 矩形坐标 - 与C++版本保持一致，顺序是: 左, 上, 右, 下
            if (label.getRect() != null) {
                float left = label.getRect().getX();
                float top = label.getRect().getY();
                float width = label.getRect().getWidth();
                float height = label.getRect().getHeight();
                
                data[baseIndex + 3] = new GeneralElement((double)left);
                data[baseIndex + 4] = new GeneralElement((double)top);
                data[baseIndex + 5] = new GeneralElement((double)(left + width));
                data[baseIndex + 6] = new GeneralElement((double)(top + height));
            }
            
            // 分类置信度
            if (label.getClassConfidence() != null) data[baseIndex + 7] = new GeneralElement(label.getClassConfidence());
            
            // 描述信息
            if (label.getDescription() != null && !label.getDescription().isEmpty()) {
                data[baseIndex + 8] = new GeneralElement(label.getDescription());
            }
            
            baseIndex += 16;
        }
        
        sample.setValues(data);
        sample.setNumberOfSignificants(data.length);
        
        return sample;
    }
    
    /**
     * 从通用样本转换为图像标签样本
     */
    @Override
    public boolean fromGeneralSample(GeneralSample sample) {
        setTime(sample);
        
        String protocol = sample.getProtocol();
        
        // 根据协议版本调用相应的处理函数
        if (TARGET_PROTOCOL.equals(protocol)) {
            return fromImageLabelSampleV2(sample);
        } else if ("image-label-sample-v1".equals(protocol)) {
            return fromImageLabelSampleV1(sample);
        }
        
        return false;
    }
    
    /**
     * 从通用样本V2版本转换为图像标签样本
     */
    private boolean fromImageLabelSampleV2(GeneralSample sample) {
        GeneralElement[] values = sample.getValues();
        if (values.length < 8) return false;
        
        if (!values[0].isValid() || values[0].getValue() != sample.getChannel()) return false;
        if (!values[1].isValid() || !values[2].isValid() || !values[3].isValid()) return false;
        
        int width = (int)values[1].getValue();
        int height = (int)values[2].getValue();
        int labelCount = (int)values[3].getValue();
        
        if (values.length != 8 + labelCount * 16) return false;
        
        // 创建并设置图像尺寸
        Types.IntSize size = new Types.IntSize();
        size.setWidth(width);
        size.setHeight(height);
        setImageSize(size);
        
        // 清空并重新创建标签列表
        labels.clear();
        for (int i = 0; i < labelCount; i++) {
            ImageLabel label = new ImageLabel();
            label.setLabelClass(ImageLabelClass.fromValue((int)values[8 + i * 16].getValue()));
            label.setId((int)values[9 + i * 16].getValue());
            
            if (values[10 + i * 16].isValid()) {
                label.setDistance(values[10 + i * 16].getValue());
            }
            
            // 创建矩形框
            float left = (float)values[11 + i * 16].getValue();
            float top = (float)values[12 + i * 16].getValue();
            float right = (float)values[13 + i * 16].getValue();
            float bottom = (float)values[14 + i * 16].getValue();
            
            Types.FloatRect rect = new Types.FloatRect();
            rect.setX(left);
            rect.setY(top);
            rect.setWidth(right - left);
            rect.setHeight(bottom - top);
            label.setRect(rect);
            
            // 设置置信度
            if (values[15 + i * 16].isValid()) {
                label.setClassConfidence(values[15 + i * 16].getValue());
            }
            
            // 设置描述信息
            if (values[16 + i * 16].isValid() && values[16 + i * 16].isText()) {
                label.setDescription(values[16 + i * 16].getText());
            }
            
            labels.add(label);
        }
        
        return true;
    }
    
    /**
     * 从通用样本V1版本转换为图像标签样本
     */
    private boolean fromImageLabelSampleV1(GeneralSample sample) {
        GeneralElement[] values = sample.getValues();
        if (values.length < 4) return false;
        
        if (!values[0].isValid() || values[0].getValue() != sample.getChannel()) return false;
        if (!values[1].isValid() || !values[2].isValid() || !values[3].isValid()) return false;
        
        int width = (int)values[1].getValue();
        int height = (int)values[2].getValue();
        int labelCount = (int)values[3].getValue();
        
        if (values.length != 4 + labelCount * 7) return false;
        
        // 创建并设置图像尺寸
        Types.IntSize size = new Types.IntSize();
        size.setWidth(width);
        size.setHeight(height);
        setImageSize(size);
        
        // 清空并重新创建标签列表
        labels.clear();
        for (int i = 0; i < labelCount; i++) {
            ImageLabel label = new ImageLabel();
            label.setLabelClass(ImageLabelClass.fromValue((int)values[4 + i * 7].getValue()));
            label.setId((int)values[5 + i * 7].getValue());
            
            if (values[6 + i * 7].isValid() && values[6 + i * 7].getValue() > 0) {
                label.setDistance(values[6 + i * 7].getValue());
            }
            
            // 创建矩形框
            float left = (float)values[7 + i * 7].getValue();
            float top = (float)values[8 + i * 7].getValue();
            float right = (float)values[9 + i * 7].getValue();
            float bottom = (float)values[10 + i * 7].getValue();
            
            Types.FloatRect rect = new Types.FloatRect();
            rect.setX(left);
            rect.setY(top);
            rect.setWidth(right - left);
            rect.setHeight(bottom - top);
            label.setRect(rect);
            
            labels.add(label);
        }
        
        return true;
    }
    
    // 协议相关常量
    public static final String TARGET_PROTOCOL = "image-label-sample-v2";
    public static final String[] PROTOCOLS = {
        "image-label-sample-v1", "image-label-sample-v2"
    };
} 